<template>
	<view v-if="show" @click="nextStep" @touchmove.stop.prevent  :style="{'--path':path,'--duration':duration+'ms'}" class="clip-container">
		<view @click.stop="nextStep" class="clip-box"></view>
		<view @click.stop class="guide-box animate__animated" :style="[msgStyles]">
			<view class="msg-label">
				{{list[index].msg}}
			</view>
			<view class="step-box">
				<view v-if="index>0" @click="lastStep" class="step-btn">
					上一步
				</view>
				<view @click="nextStep" class="step-btn">
					下一步
				</view>
				<view @click="skipStep" class="step-btn">
					跳过
				</view>
			</view>
		</view>
	</view>
</template>
<script>
	const path_default = `
		polygon(
			0% 0%, 
			0% 0%, 
			100% 0%, 
			100% 100%, 
			0% 100%, 
			0% 0%, 
			0% 0%, 
			0% 100%, 
			100% 100%, 
			100% 0%
		)
	`
	
	/**
	 * guide 引导弹窗
	 * @description 引导组件，用于教学提示、用户操作引导等内容，支持自定义组件节点自动聚焦和手动设置相对位置聚焦。组件只提供容器，内部内容由用户自定义
	 * @tutorial //git地址
	 * @property {Boolean}			show				是否展示弹窗 (默认 false )
	 * @property {Array}			list				步骤列表
	 * @property {Number}			index				当前步骤索引(默认 0 )
	 * @property {String | Number}	duration			动画时长
	 * @property {String}			unit				换算单位
	 * @event {Function} open   	弹出层打开
	 * @event {Function} close  	弹出层收起
	 * @event {Function} next   	执行下一步
	 * @event {Function} last   	执行上一步
	 * @event {Function} skip   	跳过所有步骤
	 * @event {Function} finish 	结束引导
	 * @event {Function} getQuery	获取兄弟组件布局查询对象
	 * @example <popup-guide :show="guideShow" :list="guideList" :index="guideIndex" @next="guideNext" @last="guideLast" @skip="guideSkip" @finish="guideFinish" ></popup-guide>
	 */
	export default{
		data(){
			return{
				path:path_default,
				msgStyles:{},
			}
		},
		props:{
			// 是否展示
			show:{
				default:false
			},
			// 步骤列表
			list:{
				default:[]
			},
			// 当前步骤索引
			index:{
				default:0
			},
			// 动画时长
			duration:{
				default:600
			},
			// 换算单位
			unit:{
				default:'rpx'
			}
		},
		emits:['open','close','next','last','skip','finish','getQuery'],
		watch:{
			index:{
				handler(newVal){
					if(newVal!=undefined){
						this.getCurrentPath()
					}
				}
			},
			show:{
				handler(newVal){
					if(newVal==true){
						this.getCurrentPath()
						this.$emit('open')
					}
					if(newVal==false){
						this.$emit('close')
					}
				}
			}
		},
		methods:{
			pathInit(){
				this.path = path_default
			},
			testNumber(value){
			    return /^[\+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/.test(value)
			},
			addUnit(value = '', unit = this.unit){
				value = String(value)
				return this.testNumber(value) ? `${value}${unit}` : value
			},
			isEmpty(val){
				return val===null || val === undefined || val === ''
			},
			async getCurrentPath(){
				await this.$nextTick(()=>{})
				
				let {
					ref,
					target,
					
					width,
					height,
					
					top,
					left,
					right,
					bottom,
					
					gap,
					position
					
				} = this.list[this.index]
				let x1,x2,y1,y2
				
				if(target){
					let maxWidth
					uni.getSystemInfo({
						success(res) {
							// #ifndef H5
							maxWidth = res.screenWidth
							// #endif
							// #ifdef H5
							maxWidth = res.windowWidth > 960 ? (res.windowWidth+375)/2 : res.windowWidth
							// #endif
						}
					})
					// console.log(maxWidth,'maxWidth')
					
					const targetDom = await new Promise((resolve,reject)=>{
						if(ref){
							this.$emit('getQuery',function(){
								uni.createSelectorQuery()
								.in(this.$refs[ref])
								.select(target)
								.boundingClientRect(data => {
									resolve(data)
								}).exec()
							})
						}else{
							uni.createSelectorQuery()
							.select(target)
							.boundingClientRect(data => {
								resolve(data)
							}).exec()
						}
					})
					// console.log(targetDom,'targetDom')
					width = targetDom.width
					height = targetDom.height
					top = targetDom.top
					left = targetDom.left
					right = maxWidth-targetDom.right
					//+1像素修正元素处于屏幕正中间时的msg相对位置
					if(left>right+1){
						left = ''
					}else{
						right = ''
					}
					bottom = targetDom.bottom
					// console.log(left,'left',right,'right')
					
					
					x1 = !this.isEmpty(left) ? `calc(${this.addUnit(left,'px')} + ${this.addUnit(width,'px')})` : `calc(100% - ${this.addUnit(right,'px')})`
					x2 = !this.isEmpty(left) ? `${this.addUnit(left,'px')}` : `calc(100% - ${this.addUnit(right,'px')} - ${this.addUnit(width,'px')})`
								
					y1 = !this.isEmpty(top) ? `${this.addUnit(top,'px')}` : `calc(100% - ${this.addUnit(bottom,'px')} - ${this.addUnit(height,'px')})`
					y2 = !this.isEmpty(top) ? `calc(${this.addUnit(top,'px')} + ${this.addUnit(height,'px')})` : `calc(100% - ${this.addUnit(bottom,'px')})`
					
				}else{
					x1 = !this.isEmpty(left) ? `calc(${this.addUnit(left)} + ${this.addUnit(width)})` : `calc(100% - ${this.addUnit(right)})`
					x2 = !this.isEmpty(left) ? `${this.addUnit(left)}` : `calc(100% - ${this.addUnit(right)} - ${this.addUnit(width)})`
								
					y1 = !this.isEmpty(top) ? `${this.addUnit(top)}` : `calc(100% - ${this.addUnit(bottom)} - ${this.addUnit(height)})`
					y2 = !this.isEmpty(top) ? `calc(${this.addUnit(top)} + ${this.addUnit(height)})` : `calc(100% - ${this.addUnit(bottom)})`
				}
				// 延时，解决动画丢失的问题
				await new Promise((resolve)=>{
					setTimeout(()=>{
						resolve()
					},50)
				})
				this.path = `
					polygon(
						0% 0%,
						0% ${y1},
						${x1} ${y1},
						${x1} ${y2},
						${x2} ${y2},
						${x2} ${y1},
						0% ${y1},
						0% 100%,
						100% 100%, 
						100% 0%
					)
				`
				// console.log(this.path,'path.value')
				
				
				//设置msg样式
				const msgDom = await new Promise((resolve,reject)=>{
					uni.createSelectorQuery().in(this).select('.guide-box').boundingClientRect(data => {
						resolve(data)
					}).exec()
				})
				
				let animationName
				gap = gap || 20
				position = position || 'top'
				
				if(target){
					switch (position){
						case 'top':
							if(!this.isEmpty(top)){
								top = `calc(${this.addUnit(top,'px')} - ${this.addUnit(gap)} - ${this.addUnit(msgDom.height,'px')})`
							}else{
								top = `calc(100% - ${this.addUnit(bottom,'px')} - ${this.addUnit(height,'px')} - ${this.addUnit(gap)} - ${this.addUnit(msgDom.height,'px')})`
							}
							animationName = 'backInDown'
							break;
						case 'bottom':
							if(!this.isEmpty(top)){
								top = `calc(${this.addUnit(top,'px')} + ${this.addUnit(height,'px')} + ${this.addUnit(gap)})`
							}else{
								top = `calc(100% - ${this.addUnit(bottom,'px')} + ${this.addUnit(gap)} + ${this.addUnit(msgDom.height,'px')})`
							}
							animationName = 'backInUp'
							break;
						default:
							break;
					}
					
				}else{
					switch (position){
						case 'top':
							if(top){
								top = `calc(${this.addUnit(top)} - ${this.addUnit(gap)} - ${this.addUnit(msgDom.height,'px')})`
							}else{
								top = `calc(100% - ${this.addUnit(bottom)} - ${this.addUnit(height)} - ${this.addUnit(gap)} - ${this.addUnit(msgDom.height,'px')})`
							}
							animationName = 'backInDown'
							break;
						case 'bottom':
							if(top){
								top = `calc(${this.addUnit(top)} + ${this.addUnit(height)} + ${this.addUnit(gap)})`
							}else{
								top = `calc(100% - ${this.addUnit(bottom)} + ${this.addUnit(gap)} + ${this.addUnit(msgDom.height,'px')})`
							}
							animationName = 'backInUp'
							break;
						default:
							break;
					}
					
				}
				left = target?this.addUnit(left,'px'):this.addUnit(left)
				right = target?this.addUnit(right,'px'):this.addUnit(right)
				
				this.msgStyles = {
					'top': top,
					'left':left,
					'right':right,
					'transition': `all ${this.duration}ms`,
					'animation-name': animationName,
					'-webkit-animation-name': animationName,
				}
				// console.log(this.msgStyles,'this.msgStyles')
				
			},
			nextStep(){
				if(this.list[this.index+1]){
					this.$emit('next',this.index)
				}else{
					this.pathInit()
					setTimeout(()=>{
						this.$emit('finish',this.index)
					},this.duration)
				}
			},
			lastStep(){
				this.$emit('last',this.index)
			},
			skipStep(){
				this.pathInit()
				setTimeout(()=>{
					this.$emit('skip',this.index)
				},this.duration)
			}
		},
		
		
	}
	
	
</script>

<style lang="scss">
	.shadow {
		box-shadow: 2rpx 2rpx 12rpx var(--shadow);
	}

	.clip-container {
		--path:'';
		--duration:'';
		--color:#1676ff;
		
		position: absolute;
		/* #ifdef H5 */
		width: 750rpx;
		/* #endif */
		/* #ifndef H5 */
		width: 100%;
		/* #endif */
		height: 100vh;
		top: 0;
		left: 0;
		z-index: 9996;
	}

	
	.clip-box{
		
		box-sizing: border-box;
		width: 100%;
		height: 100vh;
		transition: all var(--duration); 
		
		clip-path: var(--path);
		
		background-color: rgba(0, 0, 0, 0.5);
		
	}
	.guide-box{
		width: 50%;
		transition: all var(--duration);
		position: absolute;
		color: var(--color);
		background-color: #fff;
		border-radius: 12rpx;
		box-shadow: 2rpx 2rpx 2rpx #fff;
		box-sizing: border-box;
		padding: 20rpx;
	}
	
	.msg-label{
		color: var(--color);
		font-size: 28rpx;
	}
	
	.step-box{
		width: 100%;
		display: flex;
		align-items: center;
		justify-content: flex-end;
		padding: 20rpx 0 0 0;
		white-space: nowrap;
	}
	.step-btn{
		margin-left: 20rpx;
		box-shadow: 2rpx 2rpx 12rpx #ddd;
		padding: 6rpx 16rpx;
		border-radius: 8rpx;
		font-size: 26rpx;
	}
	
	
	@-webkit-keyframes backInDown {
		0% {
			-webkit-transform: translateY(-1200px);
			transform: translateY(-1200px);
			opacity: 0.7;
		}
	
		80% {
			-webkit-transform: translateY(0px);
			transform: translateY(0px);
			opacity: 0.7;
		}
	
		100% {
			-webkit-transform: scale(1);
			transform: scale(1);
			opacity: 1;
		}
	}
	
	
	@keyframes backInDown {
		0% {
			-webkit-transform: translateY(-1200px);
			transform: translateY(-1200px);
			opacity: 0.7;
		}
	
		80% {
			-webkit-transform: translateY(0px);
			transform: translateY(0px);
			opacity: 0.7;
		}
	
		100% {
			-webkit-transform: scale(1);
			transform: scale(1);
			opacity: 1;
		}
	}
	
	@-webkit-keyframes backInUp {
		0% {
			-webkit-transform: translateY(1200px);
			transform: translateY(1200px);
			opacity: 0.7;
		}
	
		80% {
			-webkit-transform: translateY(0px);
			transform: translateY(0px);
			opacity: 0.7;
		}
	
		100% {
			-webkit-transform: scale(1);
			transform: scale(1);
			opacity: 1;
		}
	}
	
	@keyframes backInUp {
		0% {
			-webkit-transform: translateY(1200px);
			transform: translateY(1200px);
			opacity: 0.7;
		}
	
		80% {
			-webkit-transform: translateY(0px);
			transform: translateY(0px);
			opacity: 0.7;
		}
	
		100% {
			-webkit-transform: scale(1);
			transform: scale(1);
			opacity: 1;
		}
	}
	
	.animate__animated {
		-webkit-animation-duration: var(--duration);
		animation-duration: var(--duration);
		-webkit-animation-duration: var(--duration);
		animation-duration: var(--duration);
		-webkit-animation-fill-mode: both;
		animation-fill-mode: both;
	}
	
</style>